#include "precompiled.h"
#include "protwarrior.h"
using namespace std;
using namespace weo::engine::item;
using namespace weo::engine::character::warrior;

Protection::Protection()
{
    m_AttributesVector.push_back("Health");
    m_AttributesVector.push_back("Stamina");
    m_AttributesVector.push_back("Strength");
    m_AttributesVector.push_back("Agility");
    m_AttributesVector.push_back("Armor");
    m_AttributesVector.push_back("DefenseRating");
    m_AttributesVector.push_back("DodgeRating");
    m_AttributesVector.push_back("BlockRating");
    m_AttributesVector.push_back("ParryRating");
    m_AttributesVector.push_back("BlockValue");

    Character::Init();
    m_Classnr = weo::engine::character::Character::isAllowed("Warrior");

    m_Basevalues.push_back(Attribute("Agility",93));
    m_Basevalues.push_back(Attribute("Intellect",30));
    m_Basevalues.push_back(Attribute("Strength",148));
    m_Basevalues.push_back(Attribute("Stamina",135));
    m_Basevalues.push_back(Attribute("Spirit",54));
    m_Basevalues.push_back(Attribute("AttackPower",190)); // ap
    m_Basevalues.push_back(Attribute("Health",4364)); // health
    m_Basevalues.push_back(Attribute("CritRating",5*CritRating)); // cr
    m_Basevalues.push_back(Attribute("DodgeRating",0.75f*DodgeRating));
    m_Basevalues.push_back(Attribute("DefenseRating",(20-3*5)*DefenseRating));
    m_Basevalues.push_back(Attribute("BlockRating",5*BlockRating));
    m_Basevalues.push_back(Attribute("BlockRating",5*BlockRating));
    m_Basevalues.push_back(Attribute("ParryRating",5*ParryRating));
    m_Basevalues.push_back(Attribute("ParryRating",5*ParryRating));
    m_Equip.Mode(0);
    BOOST_FOREACH(Attribute attr, m_Basevalues)
    {
        handleAttribute(attr);
    }
    m_Equip[weo::engine::item::Attribute::getAttributeValue("DefenseRating")] += 350 * DefenseRating;
    // base settings finished

    m_Buffs["Commanding Shout"].Active(true);
    m_Buffs["Spicy Crawdad"].Active(true);
    m_Buffs["Blood Pact"].Active(true);


    Buff *fortification = new Buff("Flask of Fortification");
    fortification->addAttribute(Attribute("Health", 500));
    fortification->addAttribute(Attribute("DefenseRating", 10));
    m_Buffs[fortification->Name()] = *fortification;
}
// "Health", "Stamina", "Strength", "Agility", "Armor", "DefenseRating", "DodgeRating", "BlockRating", "ParryRating", "BlockValue" 
// Tankspot effective Health calculation, modified so it actually outputs good equipment
float Protection::evaluateTF()
{
    float armor = m_Equip[33];
    float health = m_Equip[34];
    if(m_Equip.hasSpecial(99795))
    {
        health += 170;
    }
    float blockvalue = m_Equip[17] - 1;
    float mitigation = min<float>(armor / (armor + 11960.0f),0.75f);
    float dodge = m_Equip[14]/DodgeRating;
    float block = m_Equip[16]/BlockRating;
    float parry = m_Equip[15]/ParryRating;
    float missed = 5 + (m_Equip[18]/DefenseRating - 365)*0.04f;
    float mobhitspeed = 1.5f;
    if(m_Equip.hasSpecial(860996))
    {
        armor += (10.0f/mobhitspeed)*0.03f*800;
    }
    if(m_Equip.hasSpecial(105616))
    {
        health += 1750*(20.0f/180.0f);
    }
    float mobdmg = 15000;
    float reduce = 1.0f - mitigation;
    float avoidance = min<float>((dodge+parry+missed)/100.0f,1.0f);
    float crushprob = 15;
    float critprob = max<float>((490-m_Equip[18]/DefenseRating)*0.04f,0);
    float shieldblockuptime = min<float>(((mobhitspeed * 2) / 5.0f) / (1 - avoidance / 100),1);
    float blockchance = min<float>(block + shieldblockuptime * 75,100);
    // simplify(((1-avoidance) *((1-blockvalue)*block/(1-avoidance) + 2*crit/(1-avoidance) + 1.5*crush/(1-avoidance) + (1-avoidance-block-crit-crush)/(1-avoidance))));
    // -blockvalue*block + crit + 0.5000000000 crush + 1. - 1. avoidance
    float basedmg = reduce * mobdmg;
    // blockeddmg is basically the percentage of blocked dmg compared to normal dmg
    float blockeddmg = (1 - ((basedmg - blockvalue) / basedmg)) * blockchance;
    float finaldmg = max<float>((critprob + 0.5f * crushprob + 100 - avoidance - blockeddmg) * 1 / 100.0f * basedmg, 1);
    float magicaldmg = 5000 * 0.94f;
    return m_CondFactor * health/((finaldmg+magicaldmg) * 0.9f);
}
// filtering all those pala tank items
bool filterItemProtection(const weo::engine::item::Item* item)
{
    std::vector<weo::engine::item::Attribute>::const_iterator k;
    const std::vector<Attribute> *attrs = item->Attributes();
    bool badattr = false;
    for(k = attrs->begin();k!=attrs->end();k++)
    {
        switch(k->Type())
        {
        case 2:
        case 12:
        case 23:
            badattr = true;
            break;
        default:
            break;
        }
    }
    return badattr;
}
void Protection::filterEquip(std::vector<std::vector<const weo::engine::item::Item*>>& items)
{
    for(unsigned int i = 0;i<10;i++)
    {
        int subtype = 3;
        if(i == 1 || i == 3)
        {
            vector<const Item*> temp = m_Database->getPtrbyType(1,i+1);
            items.push_back(temp);
        }
        else
        {
            vector<const Item*> temp = m_Database->getPtrbyType(1,i+1,4); // plate	
            items.push_back(temp);
        }
    }
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    // main hand weapons
    vector<const Item*> mainhand;
    for(int i = 1;i<6;i++)
    {
        for(int j = 1;j<3;j++)
        {
            vector<const Item*> weapon = m_Database->getPtrbyType(4,j,i);
            vector<const Item*>::iterator it;
            for(it=weapon.begin();it!=weapon.end();it++)
            {
                mainhand.push_back(*it);
            }
        }
    }
    items.push_back(mainhand);
    items.push_back(m_Database->getPtrbyType(1,11)); // shields
    vector<const Item*> ranged;
    for(int i = 9;i<13;i++)
    {
        vector<const Item*> weapon = m_Database->getPtrbyType(4,5,i);
        vector<const Item*>::iterator it;
        for(it=weapon.begin();it!=weapon.end();it++)
        {
            ranged.push_back(*it);
        }
    }
    items.push_back(ranged); // ranged
    items.push_back(m_Database->getPtrbyType(5,0));
    std::vector<std::vector<const weo::engine::item::Item*>>::iterator it;
    for(it = items.begin();it!= items.end();it++)
    {
        it->erase(std::remove_if(it->begin(), it->end(), filterItemProtection),it->end());
    }
    Character::filterEquip(items);
}
void Protection::handleAttribute(const Attribute& attr)
{
    switch(attr.Type())
    {
    case 3:
        Character::handleAttribute(Attribute(attr.Type(),attr.Value()*1.1)); // strength *1.1f
        break;
    case 4:
        Character::handleAttribute(Attribute(attr.Type(),attr.Value()*1.05)); // stamina *1.05f
        break;
    case 17:
        m_Equip[attr.Type()] += attr.Value() * 1.3f;
        break;
    case 18:
        m_Equip[attr.Type()] += attr.Value();
        handleAttribute(Attribute(14,(attr.Value() / DefenseRating) * 0.04f * DodgeRating));
        handleAttribute(Attribute(15,(attr.Value() / DefenseRating) * 0.04f * ParryRating));
        handleAttribute(Attribute(16,(attr.Value() / DefenseRating) * 0.04f * BlockRating));
        break;
    case 33:
        m_Equip[attr.Type()] += attr.Value() * 1.1f;
        break;
    default:
        Character::handleAttribute(attr);
        break;
    }
}